package com.temp.task;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.temp.dto.RobotCampaignDTO;
import com.temp.entity.Campaign;
import com.temp.entity.ChatMessage;
import com.temp.entity.Donation;
import com.temp.entity.User;
import com.temp.enumeration.CampaignStatus;
import com.temp.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.*;

@Component
@RequiredArgsConstructor
@Slf4j
public class HandleScheduledTask {
    private final ChatMessageService chatMessageService;
    private final CampaignService campaignService;
    private final UserService userService;
    private final SystemSettingService settingService;
    private final DonationService donationService;
    private final Executor asyncExecutor;

    // 常量定义
    private static final BigDecimal MIN_DONATION = new BigDecimal("1.00");
    private static final BigDecimal MAX_DONATION = new BigDecimal("100.00");
    private static final int MIN_INTERVAL_SECONDS = 5;
    private static final int MAX_INTERVAL_SECONDS = 30;
    private static final int BATCH_SIZE = 10;
    private static final BigDecimal ONE_HUNDRED = new BigDecimal("100");
    private static final BigDecimal DEFAULT_ROBOT_PROCESS = BigDecimal.ONE;

    /**
     * 上次执行完成后，固定间隔1分钟再次执行
     */
    @Scheduled(fixedDelay = 300 * 1000)
    public void processRobotDonations() {
        if (log.isDebugEnabled()) {
            log.debug("开始自动捐款扫描: {}", LocalDateTime.now());
        }

        long startTime = System.currentTimeMillis();
        try {
            simulateRobotDonations();
        } finally {
            long duration = System.currentTimeMillis() - startTime;
            log.info("机器人捐款扫描完成，耗时 {} ms", duration);
        }
    }

    /**
     * 清空聊天数据消息，每周一凌晨 3 点执行
     */
    @Scheduled(cron = "0 0 3 ? * MON")
    @Transactional
    public void processChat() {
        log.info("触发清除聊天消息任务: {}", LocalDateTime.now());
        chatMessageService.remove(Wrappers.<ChatMessage>query().eq("1", 1));
    }

    /**
     * 模拟机器人捐款
     */
    private void simulateRobotDonations() {
        List<Campaign> activeCampaigns = getActiveCampaigns();
        if (activeCampaigns.isEmpty()) {
            if (log.isDebugEnabled()) {
                log.debug("没有找到活跃的活动");
            }
            return;
        }

        Optional<BigDecimal> settingValue = settingService.getSettingValue("five_min_robot", BigDecimal.class);

        int robotCount = ThreadLocalRandom.current().nextInt(1, settingValue.orElse(new BigDecimal("4")).intValue());
        List<User> robots = userService.selectRandomRobots(robotCount);

        if (robots.isEmpty()) {
            log.warn("没有找到可用的机器人用户");
            return;
        }

        processDonationsForRobots(robots, activeCampaigns);
    }

    /**
     * 获取活跃活动列表
     */
    private List<Campaign> getActiveCampaigns() {
        RobotCampaignDTO robotCampaignDTO = new RobotCampaignDTO();
        robotCampaignDTO.setVisibility(0);
        robotCampaignDTO.setStatus(CampaignStatus.ACTIVE.getValue());
        return campaignService.findAllCampaignByRobot(robotCampaignDTO);
    }

    /**
     * 为机器人处理捐款
     */
    private void processDonationsForRobots(List<User> robots, List<Campaign> activeCampaigns) {
        List<CompletableFuture<Void>> futures = new ArrayList<>();

        for (User robot : robots) {
            CompletableFuture<Void> future = CompletableFuture.runAsync(() ->
                            processRobotDonation(robot, new ArrayList<>(activeCampaigns)), // 复制列表避免并发修改
                    asyncExecutor
            );
            futures.add(future);
        }

        // 等待所有任务完成
        try {
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(55, TimeUnit.SECONDS);
        } catch (TimeoutException e) {
            log.warn("机器人捐款任务执行超时", e);
        } catch (Exception e) {
            log.error("机器人捐款任务执行失败", e);
        }
    }

    /**
     * 处理单个机器人的捐款
     */
    private void processRobotDonation(User robot, List<Campaign> activeCampaigns) {
        if (activeCampaigns.isEmpty()) {
            return;
        }

        Campaign campaign = selectRandomCampaign(activeCampaigns);
        if (campaign == null) {
            return;
        }

        if (isRobotLimitExceeded(campaign)) {
            activeCampaigns.remove(campaign);
            return;
        }

        BigDecimal amount = generateRandomAmount();
        boolean success = processDonationWithRetry(robot, campaign, amount, 3);

        if (success) {
            simulateUserBehaviorDelay();
        }
    }

    /**
     * 随机选择活动
     */
    private Campaign selectRandomCampaign(List<Campaign> campaigns) {
        if (campaigns.isEmpty()) {
            return null;
        }
        int index = ThreadLocalRandom.current().nextInt(campaigns.size());
        return campaigns.get(index);
    }

    /**
     * 检查机器人捐款限制
     */
    private boolean isRobotLimitExceeded(Campaign campaign) {
        try {
            BigDecimal robotAmount = Optional.ofNullable(donationService.countDonationByRobot(campaign.getId())).orElse(BigDecimal.ZERO);

            BigDecimal robotLimit = calculateRobotLimit(campaign);

            return robotAmount.compareTo(robotLimit) >= 0;
        } catch (Exception e) {
            log.error("检查机器人捐款限制失败, campaignId: {}", campaign.getId(), e);
            return true; // 出错时跳过该活动
        }
    }

    /**
     * 计算机器人捐款限额
     */
    private BigDecimal calculateRobotLimit(Campaign campaign) {
        BigDecimal process = Optional.ofNullable(campaign.getRobotDonationProcess())
                .map(BigDecimal::valueOf)
                .orElse(DEFAULT_ROBOT_PROCESS);

        return process.divide(ONE_HUNDRED, 2, RoundingMode.HALF_UP)
                .multiply(campaign.getGoalAmount());
    }

    /**
     * 生成随机金额
     */
    private BigDecimal generateRandomAmount() {
        double randomValue = ThreadLocalRandom.current().nextDouble(
                MIN_DONATION.doubleValue(),
                MAX_DONATION.doubleValue()
        );
        return BigDecimal.valueOf(randomValue).setScale(2, RoundingMode.HALF_UP);
    }

    /**
     * 带重试机制的捐款处理
     */
    private boolean processDonationWithRetry(User robot, Campaign campaign, BigDecimal amount, int maxRetries) {
        for (int attempt = 1; attempt <= maxRetries; attempt++) {
            try {
                performDonation(robot, campaign, amount);
                log.debug("机器人捐款成功: robotId={}, campaignId={}, amount={}",
                        robot.getId(), campaign.getId(), amount);
                return true;
            } catch (Exception e) {
                if (attempt == maxRetries) {
                    log.error("机器人捐款失败，达到最大重试次数: robotId={}, campaignId={}",
                            robot.getId(), campaign.getId(), e);
                    return false;
                }
                log.warn("机器人捐款失败，第{}次重试: robotId={}, campaignId={}",
                        attempt, robot.getId(), campaign.getId());
                sleepBriefly(attempt * 1000L); // 指数退避
            }
        }
        return false;
    }

    /**
     * 执行捐款操作
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void performDonation(User robot, Campaign campaign, BigDecimal amount) {
        // 使用悲观锁确保数据一致性
        Campaign lockedCampaign = campaignService.getCampaignForUpdate(campaign.getId());
        if (lockedCampaign == null || CampaignStatus.ENDED.getValue().equals(lockedCampaign.getStatus())) {
            return;
        }

        // 创建捐款记录
        Donation donation = createDonationRecord(robot, lockedCampaign, amount);
        donationService.save(donation);

        // 更新活动金额和状态
        updateCampaignAmountAndStatus(lockedCampaign, amount);

        // 更新用户余额
        updateUserBalance(lockedCampaign.getUserId(), amount);
    }

    /**
     * 创建捐款记录
     */
    private Donation createDonationRecord(User robot, Campaign campaign, BigDecimal amount) {
        Donation donation = new Donation();
        donation.setUserId(robot.getId());
        donation.setCampaignId(campaign.getId());
        donation.setAmount(amount);
        donation.setReceiptUrl("robot://donation/" + System.currentTimeMillis());
        donation.setBeneficiaryId(campaign.getUserId());
        donation.setCreatedAt(LocalDateTime.now());
        return donation;
    }

    /**
     * 更新活动金额和状态
     */
    private void updateCampaignAmountAndStatus(Campaign campaign, BigDecimal amount) {
        BigDecimal newAmount = campaign.getCurrentAmount().add(amount);
        campaign.setCurrentAmount(newAmount);

        if (newAmount.compareTo(campaign.getGoalAmount()) >= 0) {
            campaign.setStatus(CampaignStatus.ENDED.getValue());
        }
        campaign.setProgress(null);
        campaignService.updateById(campaign);
    }

    /**
     * 更新用户余额
     */
    private void updateUserBalance(Long userId, BigDecimal amount) {
        userService.updateUserBalance(userId, amount);
    }

    /**
     * 模拟用户行为延迟
     */
    private void simulateUserBehaviorDelay() {
        try {
            int delaySeconds = ThreadLocalRandom.current().nextInt(MIN_INTERVAL_SECONDS, MAX_INTERVAL_SECONDS + 1);
            TimeUnit.SECONDS.sleep(delaySeconds);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.debug("延迟被中断");
        }
    }

    /**
     * 短暂睡眠
     */
    private void sleepBriefly(long millis) {
        try {
            TimeUnit.MILLISECONDS.sleep(millis);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}